package dev.ideas.funkyj.sequence;

import dev.ideas.funkyj.function.F;
import org.junit.Assert;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

import static dev.ideas.funkyj.sequence.Sequence.*;

/**
 */
public class Parallel {

    @Test public void simple() {
        {
            long duration = System.currentTimeMillis();
            Integer s1 = from(range(1, 100000)).where(even).parallel().to(sum).get();
            duration = System.currentTimeMillis() - duration;
            System.out.println("parallel s1 = " + s1 + " duration = " + duration);
        }

        {
            long duration = System.currentTimeMillis();
            Integer s2 = from(range(1, 100000)).where(even).to(sum).get();
            duration = System.currentTimeMillis() - duration;
            System.out.println("simple s2 = " + s2 + " duration = " + duration);
        }
    }

    @Test
    public void t4() {
        Sequence<String> sequence = from(range(1, 30)).where(even).to(sleep).to(string);
        List<String> expected = sequence.asList();

        int times = 5;
        int threads = Runtime.getRuntime().availableProcessors();

        List<Long> simpleTimes = new ArrayList<Long>();
        for (int i = 0; i < times; i++) {
            long duration = System.currentTimeMillis();
            List<String> list = sequence.asList();
            duration = System.currentTimeMillis() - duration;
            simpleTimes.add(duration);
            Assert.assertEquals(list, expected);
            System.out.println("list() #" + i + ": " + duration + " " + list);
        }

        List<Long> parallelTimes = new ArrayList<Long>();
        sequence.setExecution(Executions.<String>parallelAllExecution(threads));
        for (int i = 0; i < times; i++) {
            long duration = System.currentTimeMillis();
            List<String> list = sequence.asList();
            duration = System.currentTimeMillis() - duration;
            parallelTimes.add(duration);
            Assert.assertEquals(list, expected);
            System.out.println("parallel() #" + i + ": " + duration + " " + list);
        }

        for (int i = 0; i < times; i++) {
            double v = (double) simpleTimes.get(i) / (double) parallelTimes.get(i);
            int l = (int) Math.ceil(v);
            Assert.assertTrue(l == threads);
        }
    }

    private final F<Integer,Integer> sleep = new F<Integer, Integer>() {
        @Override public Integer apply(Integer integer) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                throw new RuntimeException("", e);
            }
            return integer;
        }

        @Override public String toString() { return "zzz"; }
    };

}
